For the last 10-15 years, the best practices for managing concurrent access to resources for websites have been to back the web application with a database and have its built in concurrency control manage access in a controlled fashion. The so-called ACID (Atomicity, Consistency, Isolation, Durability) properties of databases lent themselves well to building well-behaved web applications.
Traditional relational database technology relies on maintaining a global state for maintaining ACID properties. This fact makes it difficult to build systems that are horizontally scalable.
More recently, ACID was deemed to be too restrictive for web applications, and a common architecture to manage concurrency uses the middle layer of a three tier architecture to manage application concurrency. This still relies on global state for tracking concurrency, but application designers chose how to compartmentalize the system to take advantage of natural data boundaries (called sharding) to limit the scope of concurrent access. Ad hoc concurrency control is remarkably difficult to code correctly. Most application developers do not take the time to prove that their concurrency scheme works or place safeguards to detect when concurrency assumptions are violated. The two most common failures are lost updates (effectively some form of last one out wins) or undetected application deadlocks.